#include "step.h"

namespace YQ {

FaceExtractor::FaceExtractor() : FaceExtractor (nullptr)
{ }

FaceExtractor::FaceExtractor (shared_ptr<const ImageData> img)
	: img (img),
	  detector (makeDefaultHandler<FaceDetector>()),
	  recognizer (makeDefaultHandler<FaceRecognizer>()),
	  marker (makeDefaultHandler<FaceLandmarker>())
{ }

shared_ptr<ExtractResult>
FaceExtractor::extractBiggestFaceInfo() noexcept (false)
{
	shared_ptr<ExtractResult> result = make_shared<ExtractResult>();
	result->face_info = getBiggestFace();
	result->face_points = getFacePoints (result->face_info.pos);
	result->features = getFaceFeatures (result->face_points);
	result->features_size = recognizer->GetExtractFeatureSize();
	return result;
}

void
FaceExtractor::setImage (shared_ptr<const ImageData> img)
{
	this->img = img;
}

void
QualityChecker::setImage (shared_ptr<const ImageData> img)
{
	this->img = img;
}

shared_ptr<FaceRecognizer>
FaceExtractor::getRecognizer()
{
	return recognizer;
}

SeetaFaceInfo
FaceExtractor::getBiggestFace () noexcept (false)
{
	vector<SeetaFaceInfo> faces = getFaces();
	std::partial_sort (faces.begin(), faces.begin() + 1, faces.end(), [] (SeetaFaceInfo a, SeetaFaceInfo b) {
		return a.pos.width > b.pos.width;
	});
	if (faces.empty())
		throw runtime_error ("图中不存在人脸");
	return faces[0];
}

vector<SeetaFaceInfo>
FaceExtractor::getFaces()
{
	vector<SeetaFaceInfo>faces = toVector (detector->detect (*img));
	return faces;
}

vector<SeetaPointF>
FaceExtractor::getFacePoints (const SeetaRect &face_rect)
{
	return marker->mark (*img, face_rect);
}

shared_ptr<float>
FaceExtractor::getFaceFeatures (const vector<SeetaPointF> &face_points)
{
	shared_ptr<float> features (new float[recognizer->GetExtractFeatureSize()]);
	recognizer->Extract (*img, face_points.data(), features.get());
	return features;
}

int
FaceExtractor::getExtractFeatureSize()
{
	return recognizer->GetExtractFeatureSize();
}

QualityChecker::QualityChecker (shared_ptr<const ImageData> img,
                                shared_ptr<const ExtractResult> extract_result)
	: img (img), extract_result (extract_result),
	  brightness_checker (makeDefaultHandler<QualityOfBrightness>()),
	  clarity_checker (makeDefaultHandler<QualityOfClarity>()),
	  pose_checker (makeDefaultHandler<QualityOfPoseEx>()),
	  resolution_checker (makeDefaultHandler<QualityOfResolution>()),
	  integrity_checker (makeDefaultHandler<QualityOfIntegrity>())
	  
{ }

QualityResult
QualityChecker::getBrightnessQuality()
{
	return  brightness_checker->check (
	            *img,
	            extract_result->face_info.pos,
	            extract_result->face_points.data(),
	            extract_result->features_size
	        );
}

QualityResult
QualityChecker::getClarityQuality()
{
	return  clarity_checker->check (
	            *img,
	            extract_result->face_info.pos,
	            extract_result->face_points.data(),
	            extract_result->features_size
	        );
}


QualityResult
QualityChecker::getPoseQuality()
{
	return  pose_checker->check (
	            *img,
	            extract_result->face_info.pos,
	            extract_result->face_points.data(),
	            extract_result->features_size
	        );
}

QualityResult
QualityChecker::getResolutionQuality()
{
	return  resolution_checker->check (
	            *img,
	            extract_result->face_info.pos,
	            extract_result->face_points.data(),
	            extract_result->features_size
	        );
}

QualityResult
QualityChecker::getIntergrityQuality()
{
	return  integrity_checker->check (
	            *img,
	            extract_result->face_info.pos,
	            extract_result->face_points.data(),
	            extract_result->features_size
	        );
}

}